package handler

import (
	"fmt"
	"math"
	"os"
	"strconv"
	"strings"
	"time"
	rPool "yunpan/cache/redis"
	"yunpan/db"
	"yunpan/utils"

	"github.com/garyburd/redigo/redis"
	"github.com/gin-gonic/gin"
)

//初始化信息
type MultipartUploadInfo struct{
	FileHash string
	FileSize int
	UploadID string
	ChunkSize int
	ChunkCount int
}
func InitialMuItipartUploadHandler(c *gin.Context){
	// r.ParseMultipartForm(10<<20)
	username := c.Request.Form.Get("username")
	filehash := c.Request.Form.Get("filehash")
	//filename := r.Form.Get("filename")
	filesize,err := strconv.Atoi(c.Request.Form.Get("filesize"))
	if err != nil{
		c.Writer.Write([]byte(utils.NewResMsg(-1,"params invalid",nil).JSONString()))
		return
	}
	//redis 连接
	rConn := rPool.RedisPool().Get()
	defer rConn.Close()

	upInfo := MultipartUploadInfo{
		FileHash: filehash,
		FileSize: filesize,
		UploadID: username + fmt.Sprintf("%x",time.Now().UnixNano()),
		ChunkSize: 5*1024*1024,//5MB
		ChunkCount: int(math.Ceil(float64(filesize)/(5*1024*1024))),
	}

	rConn.Do("HSET","MP_"+upInfo.UploadID,"chunkcount",upInfo.ChunkCount)
	rConn.Do("HSET","MP_"+upInfo.UploadID,"filehash",upInfo.FileHash)
	rConn.Do("HSET","MP_"+upInfo.UploadID,"filesize",upInfo.FileSize)

	c.Writer.Write([]byte(utils.NewResMsg(200,"OK",upInfo).JSONString()))

}

//上传文件分块
func UploadPartHandler(c *gin.Context){
	// r.ParseMultipartForm(100000<<20)
	//username := r.Form.Get("username")
	uploadID := c.Request.Form.Get("uploadid")
	chunkIndex := c.Request.Form.Get("index")

	//redis 连接
	rConn := rPool.RedisPool().Get()
	defer rConn.Close()

	//获得文件句柄，用于存储分块内容
	fPath := "./data/"+uploadID+"/"+chunkIndex
	os.Mkdir(fPath,0744)
	fd,err := os.Create(fPath)
	if err != nil{
		c.Writer.Write([]byte(utils.NewResMsg(-1,"Upload part failed",nil).JSONString()))
		return
	}
	defer fd.Close()

	buf := make([]byte,1024*1024)
	for{
		n,err := c.Request.Body.Read(buf)
		fd.Write(buf[:n])
		if err != nil{
			break
		}
	}

	//更新缓存状态
	rConn.Do("HSET","MP_"+uploadID,"chkidx_"+chunkIndex,1)

	//返回处理结果到客户端
	c.Writer.Write([]byte(utils.NewResMsg(200,"OK",nil).JSONString()))

}

//通知上传合并
func  CompleteUploadHandler(c *gin.Context){
	//r.ParseMultipartForm(10<<20)
	upid := c.Request.Form.Get("uploadid")
	username := c.Request.Form.Get("username")
	filehash := c.Request.Form.Get("filehash")
	filename := c.Request.Form.Get("filename")
	filesize, err := strconv.ParseInt(c.Request.Form.Get("filesize"), 10, 64)
	if err != nil{
		c.Writer.Write([]byte(utils.NewResMsg(-1,"params invalid",nil).JSONString()))
		return
	}
	//redis 连接
	rConn := rPool.RedisPool().Get()
	defer rConn.Close()
	//通过upid查询redis并判断是否所有分块上传完成
	data,err := redis.Values(rConn.Do("HGETALL","MP_"+upid))
	if err != nil{
		c.Writer.Write([]byte(utils.NewResMsg(-1,"complete upload failed",nil).JSONString()))
	}
	chunkCount := 0
	totalCount := 0
	for i :=0;i<len(data);i+=2{
		k := string(data[i].([]byte))
		v := string(data[i+1].([]byte))
		if k == "chunkcount"{
			totalCount,_ = strconv.Atoi(v)
		}else if strings.HasPrefix(k,"chkidx_")&&v=="1"{
			chunkCount++
		}
	}
	if totalCount != chunkCount{
		c.Writer.Write([]byte(utils.NewResMsg(-2,"invalid request",nil).JSONString()))
		return
	}
	//合并分块--后面做
	//更新唯一文件表和用户文件表
	retUser := db.OnUserFileUploadFinished(username,filehash,filename,filesize,"",true)
	retFile := db.OnFileUploadFinished(filehash,filename,filesize,"")
	if !retUser || !retFile{
		c.Writer.Write([]byte(utils.NewResMsg(-2,"Failed",nil).JSONString()))
		return 
	}
	
	c.Writer.Write([]byte(utils.NewResMsg(200,"OK",nil).JSONString()))

}
